﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using RAP.Framework.Libary.Utils;

namespace RAP.Framework.Libary.Utils.Collection.Iterator
{
	/// <summary>
	/// 递归迭代枚举器
	/// </summary>
	/// <typeparam name="T">迭代的成员类型</typeparam>
	public class RecursionIterator<T> : IEnumerable<RecursionIteratorItem<T>>
	{
		/// <summary>
		/// 数据源对象
		/// </summary>
		public virtual object DataSource { get; protected set; }

		/// <summary>
		/// 迭代的数据源表达式
		/// </summary>
		public virtual string IteratorExpression { get; protected set; }

		/// <summary>
		/// 在遍历每一个元素时的回调函数
		/// </summary>
		public virtual Func<RecursionIteratorItem<T>, RecursionIteratorContext, RecursionIteratorMethods> IteratorCallback { get; set; }

		/// <summary>
		/// 
		/// </summary>
		/// <param name="dataSource">数据源对象</param>
		/// <param name="iteratorExp">获取数据项的表达式，例如：Students.Subjects，该表达式会获取每个学生的每个课程数据对象，其中Students、Subjects是集合。</param>
		public RecursionIterator( object dataSource,
			string iteratorExp,
			Func<RecursionIteratorItem<T>, RecursionIteratorContext, RecursionIteratorMethods> iteratorCallback = null
		)
		{
			DataSource = dataSource ?? throw new NullReferenceException( "递归迭代[数据源]不能为null！" );
			IteratorExpression = iteratorExp ?? throw new NullReferenceException( "递归迭代[表达式]不能为空字符串！" );
			IteratorCallback = iteratorCallback;
		}

		/// <summary>
		/// 生成递归迭代的上下文集合对象
		/// </summary>
		/// <returns></returns>
		protected virtual IList<RecursionIteratorContext> GetRecursionIteratorContexts( )
		{
			var lastField = string.Empty;
			RecursionIteratorContext lastItem = null;
			return IteratorExpression.Split( '.' ).Select( field =>
			{
				var fieldExp = lastField.IsNotNullOrEmpty() ? $"{lastField}.{field}" : field;
				lastField = fieldExp;
				var item = new RecursionIteratorContext
				{
					Field = field,
					Expression = fieldExp,
					ParentItem = lastItem
				};
				if ( lastItem != null )
				{
					lastItem.ChildItem = item;
				}
				lastItem = item;
				return item;
			} ).ToList();
		}

		/// <summary>
		/// 实现IEnumerator&lt;T&gt;接口
		/// </summary>
		/// <returns></returns>
		public IEnumerator<RecursionIteratorItem<T>> GetEnumerator( )
		{
			var iteratorContexts = GetRecursionIteratorContexts();
			var currentIteratorItemIndex = 0;
			var iteratorFlag = 1;//为1：向前处理节点，为-1：退后一个节点
			var firstIteratorContext = iteratorContexts.First();
      var currentDataSource = DataSource;
			var totalCount = 0;
			while ( currentIteratorItemIndex >= 0 && currentIteratorItemIndex < iteratorContexts.Count )
			{
        var currentIteratorContext = iteratorContexts[currentIteratorItemIndex];
        if ( currentIteratorContext.DataSource == null )
				{
					var dataSource = currentDataSource.GetValue( currentIteratorContext.Field );
					if ( dataSource != null )
					{
						currentIteratorContext.DataSource = dataSource;
						currentIteratorContext.IsCollection = !( dataSource is IDictionary ) && ( dataSource is ICollection );

					}
				}

				currentDataSource = currentIteratorContext.DataSource;
				if ( currentIteratorContext.IsCollection )
				{
					//如果当前节点的数据是集合
					#region 处理集合节点
					iteratorFlag = 1;
					if ( currentIteratorItemIndex >= iteratorContexts.Count - 1 )
					{
						//如果是最后一个几点，则返回迭代对象
						var itemsEnumerator = currentIteratorContext.Enumerator;
						if ( itemsEnumerator != null )
						{
							while ( itemsEnumerator.MoveNext() )
							{
								var dataItem = itemsEnumerator.Current;
								if ( dataItem is DictionaryEntry )
								{
									dataItem = ( ( DictionaryEntry )dataItem ).Value;
								}
								var iteratorItem = new RecursionIteratorItem<T>
								{
									Value = ( T )dataItem,
									Context = currentIteratorContext
								};
								if ( IteratorCallback != null )
								{
									var callbackResult = IteratorCallback( iteratorItem, currentIteratorContext );
									if ( callbackResult != RecursionIteratorMethods.Continue )
									{
										if ( callbackResult == RecursionIteratorMethods.Break )
										{
											//中断迭代
											yield break;
										}
										else if ( callbackResult == RecursionIteratorMethods.SkipItem )
										{
											//跳过当前项
											continue;
										}
										else if ( callbackResult == RecursionIteratorMethods.SkipCollection )
										{
											//跳过当前集合
											break;
										}
									}
								}
								currentIteratorContext.CurrentData = dataItem;
								currentIteratorContext.CurrentIndex++;
								totalCount++;
								yield return iteratorItem;
							}
						}
						iteratorFlag = -1;
					}
					else
					{
						//如果当前节点不是最后一个，则循环到下一个数据项
						if ( currentIteratorContext.Enumerator?.MoveNext() != true )
						{
							//当前节点的数据集合已循环完毕
							if ( firstIteratorContext == currentIteratorContext )
							{
								//如果是第一个表达式节点的集合循环完毕，则代表整个递归遍历已完成，退出yield
								yield break;
							}
							currentIteratorContext.IsFinished = true;
							iteratorFlag = -1;
						}
						else
						{
							//更新当前节点的参数
							currentIteratorContext.CurrentIndex++;
							currentIteratorContext.CurrentData = currentDataSource = currentIteratorContext.Enumerator?.Current;
						}
						currentIteratorContext.RefreshChildItems();
					}
					#endregion 处理集合节点
				}
				else if ( currentIteratorItemIndex == 0 && iteratorContexts.Count == 1 && !currentIteratorContext.IsCollection )
				{
					//如果是第一次循环，表达式只有一级且第一级获取到的数据源不是集合，则直接只迭代一次然后退出
					var dataItem = currentDataSource;
					if ( dataItem is DictionaryEntry )
					{
						dataItem = ( ( DictionaryEntry )dataItem ).Value;
					}
					var iteratorItem = new RecursionIteratorItem<T>
					{
						Value = ( T )dataItem,
						Context = currentIteratorContext
					};
					currentIteratorContext.CurrentData = dataItem;
					totalCount++;
					IteratorCallback?.Invoke( iteratorItem, currentIteratorContext );
					yield return iteratorItem;
				}
				else
				{
					//如果当前节点不是集合，则直接对上下文的CurrentData赋值
					currentIteratorContext.CurrentData = currentDataSource;
				}
				currentIteratorItemIndex += iteratorFlag;
			}
		}

		IEnumerator IEnumerable.GetEnumerator( )
		{
			return GetEnumerator();
		}

		public IList<RecursionListItem<T>> GetList( )
		{
			var result = new List<RecursionListItem<T>>();
			foreach ( var item in this )
			{
				result.Add( new RecursionListItem<T>
				{
					Value = item.Value,
					DataSource = item.Context.DataSource,
					ParentDataSource = item.Context.ParentItem?.DataSource
				} );
			}
			return result;
		}
	}
}
